package demo;

import com.alibaba.fastjson.JSON;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.MessageQueueSelector;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageQueue;

import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 顺序消息
 * 有些消息在消费时候需要按照发送的顺序消费
 * 可以利用broker队列的将消息发送到一个队列中就可以实现顺序消费
 */
public class OrderProducerMessage {

    public static void main(String[] args) throws Exception{
        officeDemo();
    }

    private static void officeDemo() throws Exception {
        DefaultMQProducer producer = new DefaultMQProducer("AsyncGroup");
        producer.setNamesrvAddr("192.168.86.104:10001");
        producer.start();
        String[] tags = new String[]{"TagA", "TagC", "TagD"};

        // 订单列表
        List<OrderStep> orderList = buildOrders();

        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateStr = sdf.format(date);
        for (int i = 0; i < 10; i++) {
            // 加个时间前缀
            String body = dateStr + " Hello RocketMQ " + orderList.get(i);
            Message msg = new Message("demo_topic", tags[i % tags.length], "KEY" + i, body.getBytes());

            SendResult sendResult = producer.send(msg, (mqs, msg1, arg) -> {
                Long id = (Long) arg;  //根据订单id选择发送queue
                long index = id % mqs.size();
                return mqs.get((int) index);
            }, orderList.get(i).getOrderId());//订单id

            System.out.printf("SendResult status:%s, queueId:%d, body:%s%n",
                    sendResult.getSendStatus(),
                    sendResult.getMessageQueue().getQueueId(),
                    body);
        }

        producer.shutdown();
    }

    /**
     * 订单的步骤
     */
    private static class OrderStep {
        private long orderId;
        private String desc;

        public long getOrderId() {
            return orderId;
        }

        public void setOrderId(long orderId) {
            this.orderId = orderId;
        }

        public String getDesc() {
            return desc;
        }

        public void setDesc(String desc) {
            this.desc = desc;
        }

        @Override
        public String toString() {
            return "OrderStep{" +
                    "orderId=" + orderId +
                    ", desc='" + desc + '\'' +
                    '}';
        }
    }

    /**
     * 生成模拟订单数据
     */
    private static List<OrderStep> buildOrders() {
        List<OrderStep> orderList = new ArrayList<>();

        OrderStep orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111039L);
        orderDemo.setDesc("创建");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111065L);
        orderDemo.setDesc("创建");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111039L);
        orderDemo.setDesc("付款");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103117235L);
        orderDemo.setDesc("创建");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111065L);
        orderDemo.setDesc("付款");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103117235L);
        orderDemo.setDesc("付款");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111065L);
        orderDemo.setDesc("完成");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111039L);
        orderDemo.setDesc("推送");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103117235L);
        orderDemo.setDesc("完成");
        orderList.add(orderDemo);

        orderDemo = new OrderStep();
        orderDemo.setOrderId(15103111039L);
        orderDemo.setDesc("完成");
        orderList.add(orderDemo);

        return orderList;
    }

    private static void simpleDemo() throws Exception {
        DefaultMQProducer mqProducer = new DefaultMQProducer("AsyncGroup");
        mqProducer.setNamesrvAddr("192.168.86.104:10001");
        mqProducer.start();
        Map<Integer, List<String>> demoData = genDemoData();
        System.out.println(JSON.toJSON(demoData));
        try{
            for(Map.Entry<Integer,List<String>> entry:demoData.entrySet()){
                Integer key = entry.getKey();
                List<String> value = entry.getValue();
                for(String v:value) {
                    Message message = new Message("demo_topic","tag1",(key+"@@@"+v).getBytes(StandardCharsets.UTF_8));
                    mqProducer.send(message, (mqs, msg, arg) -> {
                        int idx = (Integer)arg+1;
                        MessageQueue queue = mqs.get(idx%mqs.size());
                        System.out.printf("%-10d OK %d %n",idx,queue.getQueueId());
                        return queue;
                    },key);
                }
            }
        }finally {
            mqProducer.shutdown();
        }
    }

    /**
     * 准备三组数据
     * @return {0:["k1","k2","k3"],1:["a1","a2","a3"],2[]}
     */
    private static Map<Integer, List<String>> genDemoData() {
        Map<Integer, List<String>> result = new LinkedHashMap<>();
        Map<Integer,String> prefixMap = new HashMap<>();
        prefixMap.put(0,"k");
        prefixMap.put(1,"a");
        prefixMap.put(2,"b");
        List<Integer> t = new ArrayList<>();
        for(int x=0;x<20;x++) {
            t.add(x);
        }
        Integer[] integers = t.toArray(new Integer[]{});
        for(int i=0;i<3;i++) {
            final int idx = i;
            result.put(i, Stream.of(integers).map(e->prefixMap.get(idx)+e).collect(Collectors.toList()));
        }
        return result;
    }
}
